//////////////////////////////////////////////////////////////
//
//  Description	: PDF2HTML/BMP software
//  Author	: verypdf.com Inc
//  Version	: Ver1.2
//  Platform	: Windows95/98/Me/NT/2000/XP
//  Environment	: Visual C++ 6.0
//  Date	: 2002/04/03
//
//  Copyright(C) 2000--2003 verypdf.com Inc
//      
//  Contact infomation:
//        http://www.verypdf.com/
//        support@verypdf.com
//
//  This program is shareware; you can redistribute and/or 
//  modify it under the terms of the GNU General Public License.
//  See the GNU General Public License for more details.
//
//               Portion base on Xpdf code
//         Copyright 1996-2003 Glyph && Cog, LLC
//////////////////////////////////////////////////////////////

#ifdef __GNUC__
#pragma implementation
#endif

#include "aconf.h"
#include <string.h>
#include <ctype.h>
#if HAVE_PAPER_H
#include <paper.h>
#endif
#include "gmem.h"
#include "GString.h"
#include "GList.h"
#include "GHash.h"
#include "gfile.h"
#include "Error.h"
#include "NameToCharCode.h"
#include "CharCodeToUnicode.h"
#include "UnicodeMap.h"
#include "CMap.h"
#include "BuiltinFontTables.h"
#include "FontEncodingTables.h"
#include "GlobalParams.h"

#if MULTITHREADED
#  define lockGlobalParams            gLockMutex(&mutex)
#  define lockUnicodeMapCache         gLockMutex(&unicodeMapCacheMutex)
#  define lockCMapCache               gLockMutex(&cMapCacheMutex)
#  define unlockGlobalParams          gUnlockMutex(&mutex)
#  define unlockUnicodeMapCache       gUnlockMutex(&unicodeMapCacheMutex)
#  define unlockCMapCache             gUnlockMutex(&cMapCacheMutex)
#else
#  define lockGlobalParams
#  define lockUnicodeMapCache
#  define lockCMapCache
#  define unlockGlobalParams
#  define unlockUnicodeMapCache
#  define unlockCMapCache
#endif
#include "NameToUnicodeTable.h"
#include "UnicodeMapTables.h"
#include "DisplayFontTable.h"
#include "UTF8.h"

#include <time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>

#define cidToUnicodeCacheSize     4
#define unicodeToUnicodeCacheSize 4

extern char szDllPathName[];
FILE *__fopen(char *filename,char *mode)
{
	FILE* file = fopen(filename,mode);
	if(file) return file;

	char drive[_MAX_DRIVE];
	char dir[_MAX_DIR];
	char fname[_MAX_FNAME];
	char ext[_MAX_EXT];
	_splitpath(filename, drive, dir, fname, ext );

	char szDllPathName2[MAX_PATH];
	strcpy(szDllPathName2,szDllPathName);
	strcat(szDllPathName2,"Resource\\");
	strcat(szDllPathName2,fname);
	strcat(szDllPathName2,ext);

	file = fopen(szDllPathName2,mode);
	if(file) return file;

	strcpy(szDllPathName2,szDllPathName);
	strcat(szDllPathName2,"Resource\\CMap\\");
	strcat(szDllPathName2,fname);
	strcat(szDllPathName2,ext);
	file = fopen(szDllPathName2,mode);
	if(file) return file;

	GetTempPath(MAX_PATH,szDllPathName2);
	if(szDllPathName2[strlen(szDllPathName2)-1] != '\\')
		strcat(szDllPathName2,"\\");
	strcat(szDllPathName2,filename);
	return fopen(szDllPathName2,mode);
}
//------------------------------------------------------------------------

GlobalParams *globalParams = NULL;

//------------------------------------------------------------------------
// DisplayFontParam
//------------------------------------------------------------------------

DisplayFontParam::DisplayFontParam(GString *nameA,
				   DisplayFontParamKind kindA) {
  name = nameA;
  kind = kindA;
  switch (kind) {
  case displayFontX:
    x.xlfd = NULL;
    x.encoding = NULL;
    break;
  case displayFontT1:
    t1.fileName = NULL;
    break;
  case displayFontTT:
    tt.fileName = NULL;
    break;
  }
}

DisplayFontParam::DisplayFontParam(char *nameA, char *xlfdA, char *encodingA) {
  name = new GString(nameA);
  kind = displayFontX;
  x.xlfd = new GString(xlfdA);
  x.encoding = new GString(encodingA);
}

DisplayFontParam::~DisplayFontParam() {
  delete name;
  switch (kind) {
  case displayFontX:
    if (x.xlfd) {
      delete x.xlfd;
    }
    if (x.encoding) {
      delete x.encoding;
    }
    break;
  case displayFontT1:
    if (t1.fileName) {
      delete t1.fileName;
    }
    break;
  case displayFontTT:
    if (tt.fileName) {
      delete tt.fileName;
    }
    break;
  }
}

//------------------------------------------------------------------------
// PSFontParam
//------------------------------------------------------------------------

PSFontParam::PSFontParam(GString *pdfFontNameA, GString *psFontNameA) {
  pdfFontName = pdfFontNameA;
  psFontName = psFontNameA;
}

PSFontParam::~PSFontParam() {
  delete pdfFontName;
  delete psFontName;
}

//------------------------------------------------------------------------
// parsing
//------------------------------------------------------------------------

GlobalParams::GlobalParams(char *cfgFileName)
{
	UnicodeMap *map;
	DisplayFontParam *dfp;
	GString *fileName;
	FILE *f;
	char buf[512];
	int line;
	GList *tokens;
	GString *cmd;
	char *p1, *p2;
	int i;
	
	initBuiltinFontTables();
	
	macRomanReverseMap = new NameToCharCode();
	for (i = 0; i < 256; ++i) 
	{
		if (macRomanEncoding[i]) 
		{
			macRomanReverseMap->add(macRomanEncoding[i], (CharCode)i);
		}
	}
	
	nameToUnicode = new NameToCharCode();
	cidToUnicodes = new GHash(gTrue);
	residentUnicodeMaps = new GHash();
	unicodeMaps = new GHash(gTrue);
	cMapDirs = new GHash(gTrue);
	toUnicodeDirs = new GList();
	displayFonts = new GHash();
	displayCIDFonts = new GHash();
#if HAVE_PAPER_H
	const struct paper *paperType;
	paperinit();
	paperType = paperinfo(systempapername());
	psPaperWidth = (int)paperpswidth(paperType);
	psPaperHeight = (int)paperpsheight(paperType);
	paperdone();
#else
	psPaperWidth = defPaperWidth;
	psPaperHeight = defPaperHeight;
#endif
	psDuplex = gFalse;
	psLevel = psLevel2;
	psFile = NULL;
	psFonts = new GHash();
	psEmbedType1 = gTrue;
	psEmbedTrueType = gTrue;
	psOPI = gFalse;
	textEncoding = new GString("Latin1");
#if defined(WIN32)
	textEOL = eolDOS;
#elif defined(MACOS)
	textEOL = eolMac;
#else
	textEOL = eolUnix;
#endif
	fontDirs = new GList();
	t1libControl = fontRastAALow;
	freetypeControl = fontRastAALow;
	urlCommand = NULL;
	mapNumericCharNames = gTrue;
	errQuiet = gFalse;
	
  cidToUnicodeCache = new CharCodeToUnicodeCache(cidToUnicodeCacheSize);
  unicodeToUnicodeCache =
      new CharCodeToUnicodeCache(unicodeToUnicodeCacheSize);
	unicodeMapCache = new UnicodeMapCache();
	cMapCache = new CMapCache();
	
	// set up the initial nameToUnicode table
	for (i = 0; nameToUnicodeTab[i].name; ++i) {
		nameToUnicode->add(nameToUnicodeTab[i].name, nameToUnicodeTab[i].u);
	}
	
	// set up the residentUnicodeMaps table
	map = new UnicodeMap("Latin1", latin1UnicodeMapRanges, latin1UnicodeMapLen);
	residentUnicodeMaps->add(map->getEncodingName(), map);
	map = new UnicodeMap("ASCII7", ascii7UnicodeMapRanges, ascii7UnicodeMapLen);
	residentUnicodeMaps->add(map->getEncodingName(), map);
	map = new UnicodeMap("Symbol", symbolUnicodeMapRanges, symbolUnicodeMapLen);
	residentUnicodeMaps->add(map->getEncodingName(), map);
	map = new UnicodeMap("ZapfDingbats", zapfDingbatsUnicodeMapRanges,
		zapfDingbatsUnicodeMapLen);
	residentUnicodeMaps->add(map->getEncodingName(), map);
	map = new UnicodeMap("UTF-8", &mapUTF8);
	residentUnicodeMaps->add(map->getEncodingName(), map);
	
	// default displayFonts table
	for (i = 0; displayFontTab[i].name; ++i) {
		dfp = new DisplayFontParam(displayFontTab[i].name,
			displayFontTab[i].xlfd,
			displayFontTab[i].encoding);
		displayFonts->add(dfp->name, dfp);
	}
	
	// look for a user config file, then a system-wide config file
	f = NULL;
	fileName = NULL;
	if (cfgFileName && cfgFileName[0]) 
	{
		fileName = new GString(cfgFileName);
		if (!(f = __fopen(fileName->getCString(), "r"))) 
		{
			delete fileName;
		}
	}
	if (!f) 
	{
		fileName = appendToPath(getHomeDir(), xpdfUserConfigFile);
		if (!(f = __fopen(fileName->getCString(), "r"))) 
		{
			delete fileName;
		}
	}
	if (!f) 
	{
#if defined(WIN32) && !defined(__CYGWIN32__)
		i = GetModuleFileName(NULL, buf, sizeof(buf));
		if (i <= 0 || i >= sizeof(buf)) {
			// error or path too long for buffer - just use the current dir
			buf[i] = '\0';
		}
		fileName = grabPath(buf);
		appendToPath(fileName, xpdfSysConfigFile);
#else
		fileName = new GString(xpdfSysConfigFile);
#endif
		if (!(f = __fopen(fileName->getCString(), "r"))) 
		{
			delete fileName;
		}
	}
	if (f) 
	{
		line = 1;
		while (fgets(buf, sizeof(buf) - 1, f)) 
		{
			// break the line into tokens
			tokens = new GList();
			p1 = buf;
			while (*p1) 
			{
				for (; *p1 && isspace(*p1); ++p1) ;
				if (!*p1) 
				{
					break;
				}
				if (*p1 == '"' || *p1 == '\'') 
				{
					for (p2 = p1 + 1; *p2 && *p2 != *p1; ++p2) ;
					++p1;
				}
				else 
				{
					for (p2 = p1 + 1; *p2 && !isspace(*p2); ++p2) ;
				}
				tokens->append(new GString(p1, p2 - p1));
				p1 = p2 + 1;
			}
			
			if (tokens->getLength() > 0 &&
				((GString *)tokens->get(0))->getChar(0) != '#') 
			{
				cmd = (GString *)tokens->get(0);
				if (!cmd->cmp("nameToUnicode")) 
					parseNameToUnicode(tokens, fileName, line);
				else if (!cmd->cmp("cidToUnicode")) 
					parseCIDToUnicode(tokens, fileName, line);
				else if (!cmd->cmp("unicodeMap")) 
					parseUnicodeMap(tokens, fileName, line);
				else if (!cmd->cmp("cMapDir")) 
					parseCMapDir(tokens, fileName, line);
				else if (!cmd->cmp("toUnicodeDir")) 
					parseToUnicodeDir(tokens, fileName, line);
				else if (!cmd->cmp("displayFontX")) 
					parseDisplayFont(tokens, gFalse, displayFontX, fileName, line);
				else if (!cmd->cmp("displayFontT1")) 
					parseDisplayFont(tokens, gFalse, displayFontT1, fileName, line);
				else if (!cmd->cmp("displayFontTT")) 
					parseDisplayFont(tokens, gFalse, displayFontTT, fileName, line);
				else if (!cmd->cmp("displayCIDFontX")) 
					parseDisplayFont(tokens, gTrue, displayFontX, fileName, line);
				else if (!cmd->cmp("psFile")) 
					parsePSFile(tokens, fileName, line);
				else if (!cmd->cmp("psFont")) 
					parsePSFont(tokens, fileName, line);
				else if (!cmd->cmp("psPaperSize")) 
					parsePSPaperSize(tokens, fileName, line);
				else if (!cmd->cmp("psDuplex")) 
					parseYesNo("psDuplex", &psDuplex, tokens, fileName, line);
				else if (!cmd->cmp("psLevel")) 
					parsePSLevel(tokens, fileName, line);
				else if (!cmd->cmp("psEmbedType1")) 
					parseYesNo("psEmbedType1", &psEmbedType1, tokens, fileName, line);
				else if (!cmd->cmp("psEmbedTrueType")) 
					parseYesNo("psEmbedTrueType", &psEmbedTrueType,
						tokens, fileName, line);
				else if (!cmd->cmp("psOPI")) 
					parseYesNo("psOPI", &psOPI, tokens, fileName, line);
				else if (!cmd->cmp("textEncoding")) 
					parseTextEncoding(tokens, fileName, line);
				else if (!cmd->cmp("textEOL")) 
					parseTextEOL(tokens, fileName, line);
				else if (!cmd->cmp("fontDir")) 
					parseFontDir(tokens, fileName, line);
				else if (!cmd->cmp("t1libControl")) 
					parseFontRastControl("t1libControl", &t1libControl,
						tokens, fileName, line);
				else if (!cmd->cmp("freetypeControl")) 
					parseFontRastControl("freetypeControl", &freetypeControl,
						tokens, fileName, line);
				else if (!cmd->cmp("urlCommand")) 
					parseURLCommand(tokens, fileName, line);
				else if (!cmd->cmp("mapNumericCharNames")) 
					parseYesNo("mapNumericCharNames", &mapNumericCharNames,
						tokens, fileName, line);
				else if (!cmd->cmp("errQuiet")) 
					parseYesNo("errQuiet", &errQuiet, tokens, fileName, line);
				else if (!cmd->cmp("fontpath") || !cmd->cmp("fontmap")) 
				{
					error(-1, "Unknown config file command");
					error(-1, "-- the config file format has changed");
				}
				else 
					error(-1, "Unknown config file command '%s' (%s:%d)",
						cmd->getCString(), fileName->getCString(), line);
			}
			
			deleteGList(tokens, GString);
			++line;
		}
		
		delete fileName;
	}
}

void GlobalParams::parseNameToUnicode(GList *tokens, GString *fileName,
					 int line) 
{
	GString *name;
	char *tok1, *tok2;
	FILE *f;
	char buf[256];
	int line2;
	Unicode u;
	
	if (tokens->getLength() != 2) 
	{
		error(-1, "Bad 'nameToUnicode' config file command (%s:%d)",
			fileName->getCString(), line);
		return;
	}
	name = (GString *)tokens->get(1);
	if (!(f = __fopen(name->getCString(), "r"))) 
	{
		error(-1, "Couldn't open 'nameToUnicode' file '%s'",
			name->getCString());
		return;
	}
	line2 = 1;
	while (fgets(buf, sizeof(buf), f)) 
	{
		tok1 = strtok(buf, " \t\r\n");
		tok2 = strtok(NULL, " \t\r\n");
		if (tok1 && tok2) 
		{
			sscanf(tok1, "%x", &u);
			nameToUnicode->add(tok2, u);
		} 
		else 
		{
			error(-1, "Bad line in 'nameToUnicode' file (%s:%d)", name, line2);
		}
		++line2;
	}
	fclose(f);
}

void GlobalParams::parseCIDToUnicode(GList *tokens, GString *fileName,int line) 
{
	GString *collection, *name, *old;
	
	if (tokens->getLength() != 3) 
	{
		error(-1, "Bad 'cidToUnicode' config file command (%s:%d)",
			fileName->getCString(), line);
		return;
	}
	collection = (GString *)tokens->get(1);
	name = (GString *)tokens->get(2);
	if ((old = (GString *)cidToUnicodes->remove(collection))) 
	{
		delete old;
	}
	cidToUnicodes->add(collection->copy(), name->copy());
}

void GlobalParams::parseUnicodeMap(GList *tokens, GString *fileName,int line) 
{
	GString *encodingName, *name, *old;
	
	if (tokens->getLength() != 3) 
	{
		error(-1, "Bad 'unicodeMap' config file command (%s:%d)",
			fileName->getCString(), line);
		return;
	}
	encodingName = (GString *)tokens->get(1);
	name = (GString *)tokens->get(2);
	if ((old = (GString *)unicodeMaps->remove(encodingName))) 
	{
		delete old;
	}
	unicodeMaps->add(encodingName->copy(), name->copy());
}

void GlobalParams::parseCMapDir(GList *tokens, GString *fileName, int line) 
{
	GString *collection, *dir;
	GList *list;
	
	if (tokens->getLength() != 3) 
	{
		error(-1, "Bad 'cMapDir' config file command (%s:%d)",
			fileName->getCString(), line);
		return;
	}
	collection = (GString *)tokens->get(1);
	dir = (GString *)tokens->get(2);
	if (!(list = (GList *)cMapDirs->lookup(collection))) 
	{
		list = new GList();
		cMapDirs->add(collection->copy(), list);
	}
	list->append(dir->copy());
}

void GlobalParams::parseToUnicodeDir(GList *tokens, GString *fileName,
				     int line) 
{
	if (tokens->getLength() != 2) 
	{
		error(-1, "Bad 'toUnicodeDir' config file command (%s:%d)",
			fileName->getCString(), line);
		return;
	}
	toUnicodeDirs->append(((GString *)tokens->get(1))->copy());
}

void GlobalParams::parseDisplayFont(GList *tokens, GBool isCID,
				    DisplayFontParamKind kind,
				    GString *fileName, int line) 
{
	DisplayFontParam *param, *old;
	
	if (tokens->getLength() < 2) {
		goto err1;
	}
	param = new DisplayFontParam(((GString *)tokens->get(1))->copy(), kind);
	
	switch (kind) {
	case displayFontX:
		if (tokens->getLength() != 4) {
			goto err2;
		}
		param->x.xlfd = ((GString *)tokens->get(2))->copy();
		param->x.encoding = ((GString *)tokens->get(3))->copy();
		break;
	case displayFontT1:
		if (tokens->getLength() != 3) {
			goto err2;
		}
		param->t1.fileName = ((GString *)tokens->get(2))->copy();
		break;
	case displayFontTT:
		if (tokens->getLength() != 3) {
			goto err2;
		}
		param->tt.fileName = ((GString *)tokens->get(2))->copy();
		break;
	}
	
	if (isCID) {
		if ((old = (DisplayFontParam *)displayCIDFonts->remove(param->name))) {
			delete old;
		}
		displayCIDFonts->add(param->name, param);
	} else {
		if ((old = (DisplayFontParam *)displayFonts->remove(param->name))) {
			delete old;
		}
		displayFonts->add(param->name, param);
	}
	return;
	
err2:
	delete param;
err1:
	error(-1, "Bad 'displayFont...' config file command (%s:%d)",
		fileName->getCString(), line);
}

void GlobalParams::parsePSPaperSize(GList *tokens, GString *fileName,int line) 
{
	GString *tok;
	
	if (tokens->getLength() == 2) {
		tok = (GString *)tokens->get(1);
		if (!setPSPaperSize(tok->getCString())) {
			error(-1, "Bad 'psPaperSize' config file command (%s:%d)",
				fileName->getCString(), line);
		}
	} else if (tokens->getLength() == 3) {
		tok = (GString *)tokens->get(1);
		psPaperWidth = atoi(tok->getCString());
		tok = (GString *)tokens->get(2);
		psPaperHeight = atoi(tok->getCString());
	} else {
		error(-1, "Bad 'psPaperSize' config file command (%s:%d)",
			fileName->getCString(), line);
	}
}

void GlobalParams::parsePSLevel(GList *tokens, GString *fileName, int line) 
{
	GString *tok;
	
	if (tokens->getLength() != 2) {
		error(-1, "Bad 'psLevel' config file command (%s:%d)",
			fileName->getCString(), line);
		return;
	}
	tok = (GString *)tokens->get(1);
	if (!tok->cmp("level1")) {
		psLevel = psLevel1;
	} else if (!tok->cmp("level1sep")) {
		psLevel = psLevel1Sep;
	} else if (!tok->cmp("level2")) {
		psLevel = psLevel2;
	} else if (!tok->cmp("level2sep")) {
		psLevel = psLevel2Sep;
	} else {
		error(-1, "Bad 'psLevel' config file command (%s:%d)",
			fileName->getCString(), line);
	}
}

void GlobalParams::parsePSFile(GList *tokens, GString *fileName, int line) 
{
	if (tokens->getLength() != 2) 
	{
		error(-1, "Bad 'psFile' config file command (%s:%d)",
			fileName->getCString(), line);
		return;
	}
	if (psFile) {
		delete psFile;
	}
	psFile = ((GString *)tokens->get(1))->copy();
}

void GlobalParams::parsePSFont(GList *tokens, GString *fileName, int line) 
{
	PSFontParam *param;
	
	if (tokens->getLength() != 3) {
		error(-1, "Bad 'psFont' config file command (%s:%d)",
			fileName->getCString(), line);
		return;
	}
	param = new PSFontParam(((GString *)tokens->get(1))->copy(),
		((GString *)tokens->get(2))->copy());
	psFonts->add(param->pdfFontName, param);
}

void GlobalParams::parseTextEncoding(GList *tokens, GString *fileName,
				     int line) {
	if (tokens->getLength() != 2) {
		error(-1, "Bad 'textEncoding' config file command (%s:%d)",
			fileName->getCString(), line);
		return;
	}
	delete textEncoding;
	textEncoding = ((GString *)tokens->get(1))->copy();
}

void GlobalParams::parseTextEOL(GList *tokens, GString *fileName, int line) 
{
	GString *tok;
	
	if (tokens->getLength() != 2) {
		error(-1, "Bad 'textEOL' config file command (%s:%d)",
			fileName->getCString(), line);
		return;
	}
	tok = (GString *)tokens->get(1);
	if (!tok->cmp("unix")) {
		textEOL = eolUnix;
	} else if (!tok->cmp("dos")) {
		textEOL = eolDOS;
	} else if (!tok->cmp("mac")) {
		textEOL = eolMac;
	} else {
		error(-1, "Bad 'textEOL' config file command (%s:%d)",
			fileName->getCString(), line);
	}
}

void GlobalParams::parseFontDir(GList *tokens, GString *fileName, int line) 
{
	if (tokens->getLength() != 2) {
		error(-1, "Bad 'fontDir' config file command (%s:%d)",
			fileName->getCString(), line);
		return;
	}
	fontDirs->append(((GString *)tokens->get(1))->copy());
}

void GlobalParams::parseURLCommand(GList *tokens, GString *fileName,int line) 
{
	if (tokens->getLength() != 2) {
		error(-1, "Bad 'urlCommand' config file command (%s:%d)",
			fileName->getCString(), line);
		return;
	}
	if (urlCommand) {
		delete urlCommand;
	}
	urlCommand = ((GString *)tokens->get(1))->copy();
}

void GlobalParams::parseFontRastControl(char *cmdName, FontRastControl *val,
					GList *tokens, GString *fileName,
					int line) {
	GString *tok;
	
	if (tokens->getLength() != 2) {
		error(-1, "Bad '%s' config file command (%s:%d)",
			cmdName, fileName->getCString(), line);
		return;
	}
	tok = (GString *)tokens->get(1);
	if (!setFontRastControl(val, tok->getCString())) {
		error(-1, "Bad '%s' config file command (%s:%d)",
			cmdName, fileName->getCString(), line);
	}
}

void GlobalParams::parseYesNo(char *cmdName, GBool *flag,
			      GList *tokens, GString *fileName, int line) {
	GString *tok;
	
	if (tokens->getLength() != 2) {
		error(-1, "Bad '%s' config file command (%s:%d)",
			cmdName, fileName->getCString(), line);
		return;
	}
	tok = (GString *)tokens->get(1);
	if (!tok->cmp("yes")) {
		*flag = gTrue;
	} else if (!tok->cmp("no")) {
		*flag = gFalse;
	} else {
		error(-1, "Bad '%s' config file command (%s:%d)",
			cmdName, fileName->getCString(), line);
	}
}

GlobalParams::~GlobalParams() 
{
	GHashIter *iter;
	GString *key;
	GList *list;
	
	freeBuiltinFontTables();
	
	delete macRomanReverseMap;
	
	delete nameToUnicode;
	deleteGHash(cidToUnicodes, GString);
	deleteGHash(residentUnicodeMaps, UnicodeMap);
	deleteGHash(unicodeMaps, GString);
	deleteGList(toUnicodeDirs, GString);
	deleteGHash(displayFonts, DisplayFontParam);
	deleteGHash(displayCIDFonts, DisplayFontParam);
	if (psFile) {
		delete psFile;
	}
	deleteGHash(psFonts, PSFontParam);
	delete textEncoding;
	deleteGList(fontDirs, GString);
	if (urlCommand) {
		delete urlCommand;
	}
	
	cMapDirs->startIter(&iter);
	while (cMapDirs->getNext(&iter, &key, (void **)&list)) {
		deleteGList(list, GString);
	}
	delete cMapDirs;
	
	delete cidToUnicodeCache;
	delete unicodeMapCache;
	delete cMapCache;
}

//------------------------------------------------------------------------
// accessors
//------------------------------------------------------------------------

CharCode GlobalParams::getMacRomanCharCode(char *charName) {
	return macRomanReverseMap->lookup(charName);
}

Unicode GlobalParams::mapNameToUnicode(char *charName) {
	return nameToUnicode->lookup(charName);
}

FILE *GlobalParams::getCIDToUnicodeFile(GString *collection) 
{
	GString *fileName;
	
	if (!(fileName = (GString *)cidToUnicodes->lookup(collection))) 
	{
		return NULL;
	}
	return __fopen(fileName->getCString(), "r");
}

UnicodeMap *GlobalParams::getResidentUnicodeMap(GString *encodingName) 
{
	return (UnicodeMap *)residentUnicodeMaps->lookup(encodingName);
}

FILE *GlobalParams::getUnicodeMapFile(GString *encodingName) 
{
	GString *fileName;
	
	if (!(fileName = (GString *)unicodeMaps->lookup(encodingName))) {
		return NULL;
	}
	return __fopen(fileName->getCString(), "r");
}

FILE *GlobalParams::findCMapFile(GString *collection, GString *cMapName) 
{
	GList *list;
	GString *dir;
	GString *fileName;
	FILE *f;
	int i;
	
	if (!(list = (GList *)cMapDirs->lookup(collection))) 
	{
		return NULL;
	}
	for (i = 0; i < list->getLength(); ++i) 
	{
		dir = (GString *)list->get(i);
		fileName = appendToPath(dir->copy(), cMapName->getCString());
		f = __fopen(fileName->getCString(), "r");
		delete fileName;
		if (f) 
			return f;
	}
	return NULL;
}

FILE *GlobalParams::findToUnicodeFile(GString *name) 
{
	GString *dir, *fileName;
	FILE *f;
	int i;
	
	for (i = 0; i < toUnicodeDirs->getLength(); ++i) 
	{
		dir = (GString *)toUnicodeDirs->get(i);
		fileName = appendToPath(dir->copy(), name->getCString());
		f = __fopen(fileName->getCString(), "r");
		delete fileName;
		if (f) 
			return f;
	}
	return NULL;
}

DisplayFontParam *GlobalParams::getDisplayFont(GString *fontName) {
	return (DisplayFontParam *)displayFonts->lookup(fontName);
}

DisplayFontParam *GlobalParams::getDisplayCIDFont(GString *collection) {
	return (DisplayFontParam *)displayCIDFonts->lookup(collection);
}

PSFontParam *GlobalParams::getPSFont(GString *fontName) {
	return (PSFontParam *)psFonts->lookup(fontName);
}

GString *GlobalParams::findFontFile(GString *fontName,
				    char *ext1, char *ext2) 
{
	GString *dir, *fileName;
	FILE *f;
	int i;
	
	for (i = 0; i < fontDirs->getLength(); ++i) 
	{
		dir = (GString *)fontDirs->get(i);
		if (ext1) 
		{
			fileName = appendToPath(dir->copy(), fontName->getCString());
			fileName->append(ext1);
			if ((f = __fopen(fileName->getCString(), "r"))) 
			{
				fclose(f);
				return fileName;
			}
			delete fileName;
		}
		if (ext2) 
		{
			fileName = appendToPath(dir->copy(), fontName->getCString());
			fileName->append(ext2);
			if ((f = __fopen(fileName->getCString(), "r"))) 
			{
				fclose(f);
				return fileName;
			}
			delete fileName;
		}
	}
	return NULL;
}

CharCodeToUnicode *GlobalParams::getCIDToUnicode(GString *collection) {
  GString *fileName;
  CharCodeToUnicode *ctu;

  lockGlobalParams;
  if (!(ctu = cidToUnicodeCache->getCharCodeToUnicode(collection))) {
    if ((fileName = (GString *)cidToUnicodes->lookup(collection)) &&
	(ctu = CharCodeToUnicode::parseCIDToUnicode(fileName, collection))) {
      cidToUnicodeCache->add(ctu);
    }
  }
  unlockGlobalParams;
  return ctu;
}

UnicodeMap *GlobalParams::getUnicodeMap(GString *encodingName) {
	UnicodeMap *map;
	
	if ((map = getResidentUnicodeMap(encodingName))) {
		map->incRefCnt();
		return map;
	}
	return unicodeMapCache->getUnicodeMap(encodingName);
}

CPDFMap *GlobalParams::getCMap(GString *collection, GString *cMapName) {
	return cMapCache->getCMap(collection, cMapName);
}

UnicodeMap *GlobalParams::getTextEncoding() {
	return getUnicodeMap(textEncoding);
}

//------------------------------------------------------------------------
// functions to set parameters
//------------------------------------------------------------------------

void GlobalParams::setPSFile(char *file) {
	if (psFile) {
		delete psFile;
	}
	psFile = new GString(file);
}

GBool GlobalParams::setPSPaperSize(char *size) {
	if (!strcmp(size, "letter")) {
		psPaperWidth = 612;
		psPaperHeight = 792;
	} else if (!strcmp(size, "legal")) {
		psPaperWidth = 612;
		psPaperHeight = 1008;
	} else if (!strcmp(size, "A4")) {
		psPaperWidth = 595;
		psPaperHeight = 842;
	} else if (!strcmp(size, "A3")) {
		psPaperWidth = 842;
		psPaperHeight = 1190;
	} else {
		return gFalse;
	}
	return gTrue;
}

void GlobalParams::setPSPaperWidth(int width) {
	psPaperWidth = width;
}

void GlobalParams::setPSPaperHeight(int height) {
	psPaperHeight = height;
}

void GlobalParams::setPSDuplex(GBool duplex) {
	psDuplex = duplex;
}

void GlobalParams::setPSLevel(PSLevel level) {
	psLevel = level;
}

void GlobalParams::setPSEmbedType1(GBool embed) {
	psEmbedType1 = embed;
}

void GlobalParams::setPSEmbedTrueType(GBool embed) {
	psEmbedTrueType = embed;
}

void GlobalParams::setPSOPI(GBool opi) {
	psOPI = opi;
}

void GlobalParams::setTextEncoding(char *encodingName) {
	delete textEncoding;
	textEncoding = new GString(encodingName);
}

GBool GlobalParams::setTextEOL(char *s) {
	if (!strcmp(s, "unix")) {
		textEOL = eolUnix;
	} else if (!strcmp(s, "dos")) {
		textEOL = eolDOS;
	} else if (!strcmp(s, "mac")) {
		textEOL = eolMac;
	} else {
		return gFalse;
	}
	return gTrue;
}

GBool GlobalParams::setT1libControl(char *s) {
	return setFontRastControl(&t1libControl, s);
}

GBool GlobalParams::setFreeTypeControl(char *s) {
	return setFontRastControl(&freetypeControl, s);
}

GBool GlobalParams::setFontRastControl(FontRastControl *val, char *s) {
	if (!strcmp(s, "none")) {
		*val = fontRastNone;
	} else if (!strcmp(s, "plain")) {
		*val = fontRastPlain;
	} else if (!strcmp(s, "low")) {
		*val = fontRastAALow;
	} else if (!strcmp(s, "high")) {
		*val = fontRastAAHigh;
	} else {
		return gFalse;
	}
	return gTrue;
}

void GlobalParams::setErrQuiet(GBool errQuietA) {
	errQuiet = errQuietA;
}
